/**
 * 
 */
package com.bskyb.rss.service;

import java.net.MalformedURLException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.text.Html;
import android.text.Spanned;
import android.util.Log;
import android.widget.RemoteViews;

import com.bskyb.rss.FeedItem;
import com.bskyb.rss.R;
import com.bskyb.rss.RssFeed;
import com.bskyb.rss.configure.RssFeedWidgetConfiguration;
import com.bskyb.rss.parser.RssFeedHandler;

/**
 * @author ShivakP
 */
public class RssReaderService extends Service {
	private static final String SPACE_SEPARATOR = "   ";
	private static final String FEED_FOR_FIRST_TIME = "Feed For FirstTime";
	private static final String TAG = "RssReaderService";
	protected static final String PACKAGE_NAME_FOR_MSG_HANDLER = null;
	private static String CURRENT_FEED = "CURRENT_FEED";
	public static String SITE_SKY_SPORTS = "SITE_SKYSPORTS";
	public static String SITE_SKY_NEWS = "SITE_SKYNEWS";
	public static String SITE_BBC_NEWS = "SITE_BBCNEWS";

	private static String NETWORK_PROB_TEXT = "Sorry for Inconvenience.Please Wait.Waiting for Network.NextRetry is after ";

	@Override
	public void onStart(Intent intent, int startId) {
		try{
		Log.e(TAG, "Entering onStart");
		Bundle extras = intent.getExtras();
		int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
		if (extras != null) {
			mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
		}
		AppDataHolder appDataHolder = new AppDataHolder();
		appDataHolder.setAppWidgetId(mAppWidgetId);
		appDataHolder.setContext(this);
		appDataHolder.setIntent(intent);
		new RssFeedInvokerTask().execute(appDataHolder);
		Log.e(TAG, "Exiting onStart");}catch(Throwable e){
			Log.e(TAG, "Some throwable.."+e);
		}
		
	}

	public RemoteViews buildUpdate(int appWidgetId) {
		Context context = this;
		Log.e(TAG, "Entering buildUpdate...");
		SharedPreferences prefs = context.getSharedPreferences(RssFeedWidgetConfiguration.PREFS_NAME,
		        MODE_WORLD_READABLE);
		String feedAlertType = prefs.getString(RssFeedWidgetConfiguration.PREF_PREFIX_KEY + appWidgetId
		        + R.id.widget_configuration_dropdown, "ALERTTYPE_NONE");
		String feedNewsSite = prefs.getString(RssFeedWidgetConfiguration.PREF_PREFIX_KEY + appWidgetId
		        + R.id.widget_configuration_siteselection_dropdown, "");

		String currentFeed = prefs.getString(RssFeedWidgetConfiguration.PREF_PREFIX_KEY + appWidgetId + CURRENT_FEED,
		        FEED_FOR_FIRST_TIME);

		String rssFeedUrl = "";
		String webPageUrl = "";
		String widgetImage = SITE_SKY_NEWS;

		if (SITE_SKY_SPORTS.equalsIgnoreCase(feedNewsSite)) {
			rssFeedUrl = "http://www.skysports.com/rss/0,20514,11095,00.xml";
			webPageUrl = "http://www.skysports.com";
			widgetImage = SITE_SKY_SPORTS;
		} else if (SITE_SKY_NEWS.equalsIgnoreCase(feedNewsSite)) {
			rssFeedUrl = "http://news.sky.com/sky-news/rss/home/rss.xml";
			webPageUrl = "http://www.skynews.com";
			widgetImage = SITE_SKY_NEWS;
		} else if (SITE_BBC_NEWS.equalsIgnoreCase(feedNewsSite)) {
			rssFeedUrl = "http://newsrss.bbc.co.uk/rss/newsonline_uk_edition/uk/rss.xml";
			webPageUrl = "http://news.bbc.co.uk";
			widgetImage = SITE_BBC_NEWS;
		}

		RssFeed rssFeed = invokeRssFeedService(rssFeedUrl);
		StringBuffer completeFeed = transformRssFeedToString(rssFeed);
		RemoteViews updateViews = null;

		if (completeFeed != null) {
			// This is when some problem with network happens and nothing comes
			// back
			if ("".equalsIgnoreCase(completeFeed.toString())) {
				String feedRefreshTime = prefs.getString(RssFeedWidgetConfiguration.PREF_PREFIX_KEY + appWidgetId
				        + R.id.widget_configuration_feedrefresheditbutton, "10");

				updateViews = doActionWhenHostIsResolved(context, appWidgetId, prefs, feedAlertType, currentFeed,
				        webPageUrl, widgetImage, new StringBuffer(NETWORK_PROB_TEXT).append(feedRefreshTime).append(
				                " Mins"), rssFeed);

			} else {
				updateViews = doActionWhenHostIsResolved(context, appWidgetId, prefs, feedAlertType, currentFeed,
				        webPageUrl, widgetImage, completeFeed, rssFeed);
			}

		}
		Log.e(TAG, "Exiting onStart...");
		return updateViews;

	}

	private RemoteViews doActionWhenHostIsResolved(Context context, int appWidgetId, SharedPreferences prefs,
	        String feedAlertType, String currentFeed, String webPageUrl, String widgetImage, StringBuffer completeFeed,
	        RssFeed rssFeed) {
		RemoteViews updateViews;
		updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_word);

		updateViews.setTextViewText(R.id.word_title, completeFeed.toString());
		Intent defineIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(webPageUrl));
		PendingIntent pendingIntent = PendingIntent.getActivity(context, 0 /*
																			 * no requestCode
																			 */, defineIntent, 0 /*
																								 * no
																								 * flags
																								 */);
		updateViews.setOnClickPendingIntent(R.id.word_title, pendingIntent);

		if (SITE_SKY_NEWS.equalsIgnoreCase(widgetImage)) {
			updateViews.setImageViewResource(R.id.icon, R.drawable.skynews_logo);
		} else if (SITE_SKY_SPORTS.equalsIgnoreCase(widgetImage)) {
			updateViews.setImageViewResource(R.id.icon, R.drawable.skysports_logo);
		} else if (SITE_BBC_NEWS.equalsIgnoreCase(widgetImage)) {
			updateViews.setImageViewResource(R.id.icon, R.drawable.bbcnews_logo);
		}

		raiseNotificationAndsavePrefs(appWidgetId, prefs, feedAlertType, currentFeed, completeFeed, rssFeed);
		return updateViews;
	}

	private void raiseNotificationAndsavePrefs(int appWidgetId, SharedPreferences prefs, String feedAlertType,
	        String currentFeed, StringBuffer completeFeed, RssFeed currentRssFeedObj) {
		if (!"ALERTTYPE_NONE".equalsIgnoreCase(feedAlertType)) {
			Log.e(TAG, "Entering raiseNotificationAndsavePrefs...");
			// Dont raise an alert when system boots up initially(After adding
			// widget)
			String[] changedFeedItemsAsArray = getArrayRepresentationForChangedFeed(currentFeed, completeFeed
			        .toString());
			if (doWeNeedToNotifyUser(currentFeed, completeFeed, changedFeedItemsAsArray)) {
				List<FeedItem> feedChangeList = new ArrayList<FeedItem>();
				Log.e("RssReaderService", "Feed Changed!!!");
				Log.e("RssReaderService", "Current Feed-->" + currentFeed);
				Log.e("RssReaderService", "Complete Feed-->" + completeFeed);
				Log.e("RssReaderService", "changedFeedItemsAsArray-->" + changedFeedItemsAsArray.length);
				for (String changedFeedAsString : changedFeedItemsAsArray) {
					FeedItem feedItem = currentRssFeedObj.getFeedItemBasedOnTitle(changedFeedAsString.trim());
					feedChangeList.add(feedItem);
					if (feedItem != null) {
						Log.e(TAG, "changed feed item is.." + feedItem.getDescription());
					}

				}

				raiseNotification(feedAlertType, feedChangeList);

			}

		}

		SharedPreferences.Editor editPrefs = prefs.edit();
		editPrefs.putString(RssFeedWidgetConfiguration.PREF_PREFIX_KEY + appWidgetId + CURRENT_FEED, completeFeed
		        .toString());
		editPrefs.commit();
		Log.e(TAG, "Exiting  raiseNotificationAndsavePrefs...");
	}

	private void raiseNotification(String feedAlertType, List<FeedItem> feedChangeList) {

		Log.e(TAG, "Raising Notification!!!!");
		// CharSequence from = "Latest News Alert!!";
		NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

		for (FeedItem changedFeedItem : feedChangeList) {

			Notification notification = new Notification(R.drawable.alert_small, changedFeedItem.getTitle(), System
			        .currentTimeMillis());
			RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.widget_notification);
			contentView.setTextViewText(R.id.newswidgetnotificationheadline, changedFeedItem.getTitle());
			contentView.setTextViewText(R.id.newswidgetnotificationdescription, changedFeedItem.getDescription());
			notification.contentView = contentView;
			if (changedFeedItem.getLink() != null) {
				Intent defineIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(changedFeedItem.getLink()));
				PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, defineIntent, 0);
				notification.contentIntent = pendingIntent;
			}

			// notification.setLatestEventInfo(this, from, changedFeedItem.getTitle(),
			// pendingIntent);
			if ("ALERTTYPE_SOUND".equalsIgnoreCase(feedAlertType)) {
				notification.defaults |= Notification.DEFAULT_SOUND;
			} else if ("ALERTTYPE_SOUND".equalsIgnoreCase(feedAlertType)) {
				notification.defaults |= Notification.DEFAULT_VIBRATE;

			}
			nm.notify(R.string.app_notification_id, notification);
		}

	}

	private boolean doWeNeedToNotifyUser(String currentFeed, StringBuffer completeFeed, String[] changedFeedItemsAsArray) {
		return changedFeedItemsAsArray != null && changedFeedItemsAsArray.length > 0
		        && !FEED_FOR_FIRST_TIME.equalsIgnoreCase(currentFeed)
		        && !completeFeed.toString().startsWith(NETWORK_PROB_TEXT)
		        && !currentFeed.toString().startsWith(NETWORK_PROB_TEXT);
	}

	private String[] getArrayRepresentationForChangedFeed(String currentFeed, String completeFeed) {
		String[] currentFeedAsTokens = currentFeed.split("\\s{3}");
		String[] completeFeedAsTokens = completeFeed.split("\\s{3}");
		ArrayList<String> currentFeedAsTokensAsList = new ArrayList<String>(Arrays.asList(currentFeedAsTokens));
		ArrayList<String> completeFeedAsTokensAsList = new ArrayList<String>(Arrays.asList(completeFeedAsTokens));
		completeFeedAsTokensAsList.removeAll(currentFeedAsTokensAsList);
		String[] array = (String[]) completeFeedAsTokensAsList.toArray(new String[completeFeedAsTokensAsList.size()]);

		return array;
	}

	protected StringBuffer transformRssFeedToString(RssFeed rssFeed) {
		StringBuffer completeFeed = new StringBuffer();
		if (rssFeed != null) {
			for (FeedItem feedItem : rssFeed.getFeedList()) {
				String formattedString = MessageFormat.format("<a href=\"{0}\">{1}</a>  ", feedItem.getLink(), feedItem
				        .getTitle());
				Spanned fromHtml = Html.fromHtml(formattedString);
				completeFeed.append(fromHtml);
				completeFeed.append(SPACE_SEPARATOR);
			}
		}
		return completeFeed;
	}

	private RssFeed invokeRssFeedService(String rssFeedUrl) {
		RssFeed rssFeed = null;
		if (!"".equalsIgnoreCase(rssFeedUrl)) {
			Log.e(TAG, "Invoking feedservice!! with URL.." + rssFeedUrl);
			RssFeedHandler rssFeedHandler = new RssFeedHandler();
			try {
				rssFeed = rssFeedHandler.createFeed(new URL(rssFeedUrl));
			} catch (MalformedURLException e) {
				Log.e(TAG, "Malformed URl Exception", e);
			} catch (Throwable e) {
				Log.e(TAG, "Some throwable exception", e);
			}
		}
		return rssFeed;
	}

	/*
	 * (non-Javadoc)
	 * @see android.app.Service#onBind(android.content.Intent)
	 */
	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return null;
	}

	private class RssFeedInvokerTask extends AsyncTask<AppDataHolder, Void, AppDataHolder> {
		@Override
		protected void onPostExecute(AppDataHolder appDataHolder) {
			try {
				Log.e(TAG, "Entering onPostExecute");
				if (appDataHolder.getRemoteViews() != null) {
					AppWidgetManager manager = AppWidgetManager.getInstance(appDataHolder.getContext());
					manager.updateAppWidget(appDataHolder.getAppWidgetId(), appDataHolder.getRemoteViews());
				}
				Log.e(TAG, "Exiting onPostExecute");
			} catch (Throwable t) {
				Log.e(TAG, "Some throwable exception", t);
			}

		}

		@Override
		protected AppDataHolder doInBackground(AppDataHolder... appDataHolderParamArray) {
			AppDataHolder appDataHolder = new AppDataHolder();
			try {
				Log.e(TAG, "Entering doInBackground");
				AppDataHolder appDataHolderParam = appDataHolderParamArray[0];
				Bundle extras = appDataHolderParam.getIntent().getExtras();
				int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
				if (extras != null) {
					mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,
					        AppWidgetManager.INVALID_APPWIDGET_ID);
				}
				RemoteViews remoteViews = buildUpdate(mAppWidgetId);
				appDataHolder.setRemoteViews(remoteViews);
				appDataHolder.setIntent(appDataHolderParam.getIntent());
				appDataHolder.setContext(appDataHolderParam.getContext());
				appDataHolder.setAppWidgetId(mAppWidgetId);
				Log.e(TAG, "Exiting doInBackground");
			} catch (Throwable t) {
				Log.e(TAG, "Some throwable exception", t);
			}
			return appDataHolder;

		}

	}

	private class AppDataHolder {
		private RemoteViews remoteViews;
		private Intent intent;
		private Context context;
		private int appWidgetId;

		public void setRemoteViews(RemoteViews remoteViews) {
			this.remoteViews = remoteViews;
		}

		public RemoteViews getRemoteViews() {
			return remoteViews;
		}

		public void setIntent(Intent intent) {
			this.intent = intent;
		}

		public Intent getIntent() {
			return intent;
		}

		public void setContext(Context context) {
			this.context = context;
		}

		public Context getContext() {
			return context;
		}

		public void setAppWidgetId(int appWidgetId) {
			this.appWidgetId = appWidgetId;
		}

		public int getAppWidgetId() {
			return appWidgetId;
		}

	}

}
